#include "MoreParticlesTest.h"
#include "math/Vector2.h"
#include "TestManager.h"

#include <cassert>
#include <cmath>

using namespace phynet;

const Real MoreParticlesTest::PARTICLE_STARTING_SPEED = 20.0f;
const Real MoreParticlesTest::PARTICLE_STARTING_ANGLE_GRAD = 45.0f;
const Real MoreParticlesTest::PARTICLE_STARTING_DAMPING = 0.999f;

const phynet::Real MoreParticlesTest::PARTICLE_MASS[NUM_PARTICLES] = {1.0f, 0.2f, 1.0f, 5.0f};
const phynet::Real MoreParticlesTest::PARTICLE_SIZE[NUM_PARTICLES] = {0.1f, 0.2f, 0.3f, 0.4f};

MoreParticlesTest::MoreParticlesTest(TestManager* testManager)
	: Test(testManager)
	, m_gravityFG(math::Vector2(0.0f, -9.81f))
{
	srand(NULL);
	Init();
}

MoreParticlesTest::~MoreParticlesTest()
{
}

void MoreParticlesTest::Init()
{
	m_engine.Init();

	m_nextParticleSpeed = PARTICLE_STARTING_SPEED;
	m_nextParticleAngleGrad = PARTICLE_STARTING_ANGLE_GRAD;
	m_nextParticleDamping = PARTICLE_STARTING_DAMPING;

	phy::ParticleWorld2D& world = m_engine.GetWorld();

	world.AddParticles(m_particle, NUM_PARTICLES);
	world.AddForce(&m_gravityFG);
	world.AddForce(&m_windFG);
	world.AddForceOnParticles(&m_gravityFG, m_particle, NUM_PARTICLES);
	world.AddForceOnParticles(&m_windFG, m_particle + 1, NUM_PARTICLES - 1); //first particle doesn't feel the wind ;)

	Shoot();
}

void MoreParticlesTest::Shoot()
{
	m_windFG.Set(math::Vector2( (10-rand()%21)/10.0f, (10-rand()%21)/10.0f), (rand()%10)/10.0f);

	const Real angleRad = m_nextParticleAngleGrad * 3.1415926f / 180.0f;
	const math::Vector2 startingVel(m_nextParticleSpeed*cosf(angleRad), m_nextParticleSpeed*sinf(angleRad));
	for(int i=0; i<NUM_PARTICLES; ++i)
		m_particle[i].Init(PARTICLE_MASS[i], PARTICLE_SIZE[i], m_nextParticleDamping, 1.0f, math::Vector2(-15.0f, 0.0f), startingVel); //mass, radius, damping, position, velocity...
}

void MoreParticlesTest::Render(Renderer& renderer) const
{
	typedef math::Vector2 Vector2;
	typedef phy::Particles2D Particles;

	const phy::ParticleWorld2D& world = m_engine.GetWorld();
	const Real speed = m_testManager->GetSlowMotion();

	// instruction
	char buffer[100];
	sprintf(buffer, "Ciao!! e' passato: %.2f  velocita' %.2fX", world.GetTime(), speed);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Speed %.2f (-V/+B)", m_nextParticleSpeed);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Direction %.2f (-C/+X)", m_nextParticleAngleGrad);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "Damping %.3f (-K/+L)", m_nextParticleDamping);
	renderer.RenderTextLine(buffer);
	sprintf(buffer, "");
	renderer.RenderTextLine(buffer);

	// axis
	renderer.RenderLine(Vector2(-50.0f, 0.0f), Vector2(50.0f, 0.0f));
	renderer.RenderLine(Vector2(0.0f, -50.0f), Vector2(0.0f, 50.0f));

	// cannon
	const Real angleRad = m_nextParticleAngleGrad * 3.1415926f / 180.0f;
	Vector2 direct(cosf(angleRad), sinf(angleRad));
	renderer.RenderLine(Vector2(-15.0f, 0.0f), Vector2(-15.0f, 0.0f) + direct);

	// wind
	renderer.RenderLine(Vector2(0.1f, 0.1f), Vector2(0.1f, 0.1f) + m_windFG.GetBaseWindForce()*5.0f);

	// world
	const Particles& particles = world.GetParticles();
	for (Particles::const_iterator i = particles.begin(); i != particles.end(); ++i)
		renderer.RenderCircle((*i)->GetPosition(), (*i)->GetRadius(), 12);
}

void MoreParticlesTest::Update(float i_elapsedTime)
{
	m_engine.Update(i_elapsedTime);
}

void MoreParticlesTest::OnKeyPressed(int keyCode)
{
	if (keyCode == sf::Key::S)
	{
		Shoot();
	}
	else if (keyCode == sf::Key::X)
	{
		m_nextParticleAngleGrad += 1.0f;
	}
	else if (keyCode == sf::Key::C)
	{
		m_nextParticleAngleGrad -= 1.0f;
	}
	else if (keyCode == sf::Key::B)
	{
		m_nextParticleSpeed += 1.0f;
	}
	else if (keyCode == sf::Key::V)
	{
		m_nextParticleSpeed -= 1.0f;
	}
	else if (keyCode == sf::Key::L)
	{
		if(math::LessThan(m_nextParticleDamping,1.0f))
			m_nextParticleDamping += 0.001f;
	}
	else if (keyCode == sf::Key::K)
	{
		m_nextParticleDamping -= 0.001f;
	}
}
